package com.open.rbac.controller.sys;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.open.center.common.constant.OpenConstant;
import com.open.center.common.model.CommonResult;
import com.open.center.common.util.JSON;
import com.open.rbac.config.annotation.TokenUserId;
import com.open.rbac.constant.ImmutableUser;
import com.open.rbac.constant.MenuType;
import com.open.rbac.model.VueRouter;
import com.open.rbac.model.dto.sys.MenuDto;
import com.open.rbac.model.dto.sys.RoleMenuRelDto;
import com.open.rbac.model.vo.sys.MenuVo;
import com.open.rbac.service.sys.IMenuService;
import com.open.rbac.service.sys.IRoleMenuRelService;

/**
 * 菜单控制器
 *
 * @author Riche's
 * @since 2022/8/25
 */

@Slf4j
@Tag(name = "路由管理", description = "路由控制器")
@ApiResponses(value = {
    @ApiResponse(responseCode = "200", description = "成功",
        content = {@Content(schema = @Schema(implementation = VueRouter.class))}),
})
@RequiredArgsConstructor
@Validated
@RestController
@RequestMapping("/v1/sys/router")
public class RouterController {

    private final IMenuService menuService;
    private final IRoleMenuRelService roleMenuRelService;

    private final Set<String> immutableUserIds =
        Arrays.stream(ImmutableUser.values()).map(ImmutableUser::id).collect(Collectors.toSet());


    @Operation(summary = "查询用户路由列表")
    @GetMapping("/list")
    public CommonResult<List<VueRouter>> list(@TokenUserId String userId) {
        long beginTime = System.currentTimeMillis();
        MenuVo menuVo = new MenuVo();
        menuVo.setEnable(true);
        // 1. 查询已启用的菜单树
        List<MenuDto> menuDtos = menuService.tree(menuVo);
        List<VueRouter> vueRouters = new ArrayList<>();
        if (immutableUserIds.contains(userId)) {
            // 超级用户直接构建全量路由
            superRouters(menuDtos, vueRouters);
        } else {
            // 2. 查询用户的菜单列表
            List<RoleMenuRelDto> userMenuRelDtos = roleMenuRelService.listByUserId(userId);
            if (CollectionUtils.isEmpty(userMenuRelDtos)) {
                return CommonResult.success(new ArrayList<>());
            }
            Set<String> userMenuIds = userMenuRelDtos.stream()
                .map(RoleMenuRelDto::getMenuId)
                .collect(Collectors.toSet());
            // 3. 构建前端路由树
            buildRouters(userMenuIds, menuDtos, vueRouters);
        }
        long endTime = System.currentTimeMillis();
        log.info("查询用户路由树耗时：{} 毫秒", (endTime - beginTime));
        log.info("路由信息：{}", JSON.toJson(vueRouters));
        return CommonResult.success(vueRouters);
    }

    private void buildRouters(Set<String> uMenuIds, List<MenuDto> menuDtos, List<VueRouter> vueRouters) {
        if (CollectionUtils.isEmpty(menuDtos)) {
            return;
        }
        for (MenuDto menuDto : menuDtos) {
            if (uMenuIds.contains(menuDto.getId()) && MenuType.FUNCTION != menuDto.getType()) {
                VueRouter vueRouter = transfer(menuDto);
                if (!CollectionUtils.isEmpty(menuDto.getChildren())) {
                    vueRouter.getMeta().setAuths(menuDto.getChildren().stream()
                            .filter(m -> MenuType.FUNCTION == m.getType())
                            .filter(m -> uMenuIds.contains(m.getId()))
                            .map(MenuDto::getAuthKey)
                            .filter(StringUtils::hasText).toList());
                    if (MenuType.FUNCTION != menuDto.getChildren().getFirst().getType()) {
                        List<VueRouter> subRouters = new ArrayList<>();
                        vueRouter.setChildren(subRouters);
                        buildRouters(uMenuIds, menuDto.getChildren(), subRouters);
                    }
                }
                vueRouters.add(vueRouter);
            }
        }
    }

    // [管理员、超级用户]构建全量的前端路由树
    private void superRouters(List<MenuDto> menuDtos, List<VueRouter> vueRouters) {
        if (CollectionUtils.isEmpty(menuDtos)) {
            return;
        }
        for (MenuDto menuDto : menuDtos) {
            if (MenuType.FUNCTION != menuDto.getType()) {
                VueRouter vueRouter = transfer(menuDto);
                if (!CollectionUtils.isEmpty(menuDto.getChildren())) {
                    vueRouter.getMeta().setAuths(menuDto.getChildren().stream()
                        .filter(m -> MenuType.FUNCTION == m.getType())
                        .map(MenuDto::getAuthKey)
                        .filter(StringUtils::hasText).toList());
                    if (MenuType.FUNCTION != menuDto.getChildren().getFirst().getType()) {
                        List<VueRouter> subRouters = new ArrayList<>();
                        vueRouter.setChildren(subRouters);
                        superRouters(menuDto.getChildren(), subRouters);
                    }
                }
                vueRouters.add(vueRouter);
            }
        }
    }

    private VueRouter transfer(MenuDto menuDto) {
        VueRouter vueRouter = new VueRouter();
        vueRouter.setName(menuDto.getRouterName());
        vueRouter.setPath(menuDto.getRouterPath());
        vueRouter.setComponent(menuDto.getRouterComponent());
        vueRouter.setShowParent(!OpenConstant.ROOT_ORGANIZATION_ID.equals(menuDto.getParentId()));
        VueRouter.Meta meta = new VueRouter.Meta();
        meta.setTitle(menuDto.getName());
        meta.setIcon(menuDto.getIcon());
        meta.setRank(menuDto.getSort());
        vueRouter.setMeta(meta);
        return vueRouter;
    }


    @Operation(summary = "Mock用户路由列表")
    @GetMapping("/mock")
    public CommonResult<List<VueRouter>> mock() {
        List<VueRouter> vueRouters = new ArrayList<>();
        VueRouter vueRouter1 = new VueRouter();
        vueRouter1.setPath("/admin");
        vueRouter1.setName("Admin");
        vueRouter1.setRedirect("/admin/user");
        VueRouter.Meta meta1 = new VueRouter.Meta();
        meta1.setTitle("系统管理");
        meta1.setIcon("mdi-light:settings");
        meta1.setRank(8);
        vueRouter1.setMeta(meta1);
        vueRouters.add(vueRouter1);

        List<VueRouter> vueRouter1s = new ArrayList<>();
        vueRouter1.setChildren(vueRouter1s);

        VueRouter vueRouter2 = new VueRouter();
        vueRouter2.setPath("/admin/user");
        vueRouter2.setName("User");
        vueRouter2.setComponent("admin/user/index");
        vueRouter2.setShowParent(true);
        VueRouter.Meta meta2 = new VueRouter.Meta();
        meta2.setTitle("用户管理");
        meta2.setIcon("mdi-light:account");
        vueRouter2.setMeta(meta2);
        vueRouter1s.add(vueRouter2);

        VueRouter vueRouter3 = new VueRouter();
        vueRouter3.setPath("/admin/role");
        vueRouter3.setName("Role");
        vueRouter3.setComponent("admin/role/index");
        vueRouter3.setShowParent(true);
        VueRouter.Meta meta3 = new VueRouter.Meta();
        meta3.setTitle("角色管理");
        meta3.setIcon("material-symbols-light:supervisor-account-outline");
        vueRouter3.setMeta(meta3);
        vueRouter1s.add(vueRouter3);

        VueRouter vueRouter4 = new VueRouter();
        vueRouter4.setPath("/admin/menu");
        vueRouter4.setName("Menu");
        vueRouter4.setComponent("admin/menu/index");
        vueRouter4.setShowParent(true);
        VueRouter.Meta meta4 = new VueRouter.Meta();
        meta4.setTitle("菜单管理");
        meta4.setIcon("mdi-light:format-align-right");
        vueRouter4.setMeta(meta4);
        vueRouter1s.add(vueRouter4);

        VueRouter vueRouter5 = new VueRouter();
        vueRouter5.setPath("/admin/organization");
        vueRouter5.setName("Organization");
        vueRouter5.setComponent("admin/organization/index");
        vueRouter5.setShowParent(true);
        VueRouter.Meta meta5 = new VueRouter.Meta();
        meta5.setTitle("组织机构");
        meta5.setIcon("mdi-light:sitemap");
        vueRouter5.setMeta(meta5);
        vueRouter1s.add(vueRouter5);
        return CommonResult.success(vueRouters);
    }
}
